001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018: package org.apache.lenya.cms.site.tree2;
019:
020: import java.util.ArrayList;
021: import java.util.Arrays;
022: import java.util.HashMap;
023: import java.util.List;
024: import java.util.Map;
025: import java.util.Set;
026:
027: import org.apache.avalon.framework.container.ContainerUtil;
028: import org.apache.avalon.framework.logger.AbstractLogEnabled;
029: import org.apache.avalon.framework.logger.Logger;
030: import org.apache.lenya.cms.publication.DocumentFactory;
031: import org.apache.lenya.cms.site.Link;
032: import org.apache.lenya.cms.site.SiteException;
033: import org.apache.lenya.cms.site.SiteNode;
034: import org.apache.lenya.cms.site.SiteStructure;
035: import org.apache.lenya.cms.site.tree.SiteTreeNode;
036: import org.apache.lenya.util.Assert;
037: import org.apache.lenya.util.StringUtil;
038:
039: /**
040: * Site tree node.
041: */
042: public class TreeNodeImpl extends AbstractLogEnabled implements
043: TreeNode {
044:
045: private TreeNode parent;
046: private String name;
047:
048: /**
049: * A top level node.
050: * @param parent The parent.
051: * @param name The name.
052: * @param visible The navigation visibility.
053: * @param logger The logger.
054: */
055: public TreeNodeImpl(TreeNode parent, String name, boolean visible,
056: Logger logger) {
057: ContainerUtil.enableLogging(this , logger);
058: Assert.notNull("name", name);
059: this .name = name;
060: this .parent = parent;
061: this .isVisible = visible;
062: }
063:
064: /**
065: * Sets the UUID.
066: * @param uuid The UUID.
067: */
068: protected void setUuid(String uuid) {
069: Assert.notNull("uuid", uuid);
070: if (this .language2link.keySet().size() > 0) {
071: throw new RuntimeException(
072: "Can't set the UUID if the node has links.");
073: }
074:
075: if (this .uuid != null) {
076: String[] languages = getLanguages();
077: for (int i = 0; i < languages.length; i++) {
078: getTree().linkRemoved(this .uuid, languages[i]);
079: }
080: }
081:
082: this .uuid = uuid;
083:
084: String[] languages = getLanguages();
085: for (int i = 0; i < languages.length; i++) {
086: try {
087: getTree().linkAdded(getLink(languages[i]));
088: } catch (SiteException e) {
089: throw new RuntimeException(e);
090: }
091: }
092: }
093:
094: public void delete() {
095: deleteInternal();
096: changed();
097: }
098:
099: protected void deleteInternal() {
100: String[] languages = getLanguages();
101: for (int i = 0; i < languages.length; i++) {
102: removeLinkInternal(languages[i]);
103: }
104: SiteNode[] children = getChildren();
105: for (int i = 0; i < children.length; i++) {
106: ((TreeNodeImpl) children[i]).deleteInternal();
107: }
108: ((TreeNodeImpl) this .parent).removeChild(getName());
109: }
110:
111: private Map language2link = new HashMap();
112: private String uuid;
113: private boolean isVisible;
114:
115: public String[] getLanguages() {
116: Set languages = this .language2link.keySet();
117: return (String[]) languages
118: .toArray(new String[languages.size()]);
119: }
120:
121: public Link getLink(String language) throws SiteException {
122: Assert.notNull("language", language);
123: if (!this .language2link.containsKey(language)) {
124: throw new SiteException("No link contained for language ["
125: + language + "]");
126: }
127: return (Link) this .language2link.get(language);
128: }
129:
130: public String getName() {
131: return this .name;
132: }
133:
134: public SiteNode getParent() throws SiteException {
135: if (isTopLevel()) {
136: throw new SiteException("This is a top level node.");
137: }
138: return (SiteNode) this .parent;
139: }
140:
141: public String getPath() {
142: return this .parent.getPath() + "/" + getName();
143: }
144:
145: public SiteStructure getStructure() {
146: return getTree();
147: }
148:
149: public String getUuid() {
150: return this .uuid;
151: }
152:
153: public boolean hasLink(String language) {
154: Assert.notNull("language", language);
155: return this .language2link.containsKey(language);
156: }
157:
158: public boolean isTopLevel() {
159: return this .parent instanceof RootNode;
160: }
161:
162: public boolean isVisible() {
163: return this .isVisible;
164: }
165:
166: public void setVisible(boolean visibleInNav) {
167: this .isVisible = visibleInNav;
168: changed();
169: }
170:
171: protected void changed() {
172: getTree().changed();
173: }
174:
175: public SiteTreeNode[] getPrecedingSiblings() {
176: SiteNode[] children = this .parent.getChildren();
177: int pos = Arrays.asList(children).indexOf(this );
178: List siblings = new ArrayList();
179: for (int i = 0; i < pos; i++) {
180: siblings.add(children[i]);
181: }
182: return (SiteTreeNode[]) siblings
183: .toArray(new TreeNodeImpl[siblings.size()]);
184: }
185:
186: public SiteTreeNode[] getNextSiblings() {
187: SiteNode[] children = this .parent.getChildren();
188: int pos = Arrays.asList(children).indexOf(this );
189: List siblings = new ArrayList();
190: for (int i = pos + 1; i < children.length; i++) {
191: siblings.add(children[i]);
192: }
193: return (SiteTreeNode[]) siblings
194: .toArray(new TreeNodeImpl[siblings.size()]);
195: }
196:
197: public SiteTreeImpl getTree() {
198: return this .parent.getTree();
199: }
200:
201: protected Link addLink(String lang, String label) {
202: Assert.notNull("language", lang);
203: Assert.notNull("label", label);
204: Link link = addLinkInternal(lang, label);
205: changed();
206: return link;
207: }
208:
209: protected Link addLinkInternal(String lang, String label) {
210: Assert.notNull("language", lang);
211: Assert.notNull("label", label);
212: if (this .language2link.containsKey(lang)) {
213: throw new RuntimeException("The language [" + lang
214: + "] is already contained.");
215: }
216: DocumentFactory factory = getTree().getPublication()
217: .getFactory();
218: Link link = new SiteTreeLink(factory, this , label, lang);
219: this .language2link.put(lang, link);
220: getTree().linkAdded(link);
221: return link;
222: }
223:
224: protected void removeLink(String language) {
225: removeLinkInternal(language);
226: deleteIfEmpty();
227: changed();
228: }
229:
230: protected void removeLinkInternal(String language) {
231: Assert.notNull("language", language);
232: this .language2link.remove(language);
233: getTree().linkRemoved(getUuid(), language);
234: }
235:
236: protected void deleteIfEmpty() {
237: if (isEmpty()) {
238: deleteInternal();
239: }
240: }
241:
242: protected boolean isEmpty() {
243: return this .language2link.isEmpty()
244: && this .name2child.isEmpty();
245: }
246:
247: public String toString() {
248: return getPath() + "[" + StringUtil.join(getLanguages(), ",")
249: + "]";
250: }
251:
252: private List children = new ArrayList();
253:
254: public SiteNode[] getChildren() {
255: return (SiteNode[]) this .children
256: .toArray(new SiteNode[this .children.size()]);
257: }
258:
259: public SiteNode[] preOrder() {
260: List preOrder = new ArrayList();
261: preOrder.add(this );
262: SiteNode[] children = getChildren();
263: for (int i = 0; i < children.length; i++) {
264: TreeNode child = (TreeNode) children[i];
265: preOrder.addAll(Arrays.asList(child.preOrder()));
266: }
267: return (SiteNode[]) preOrder.toArray(new SiteNode[preOrder
268: .size()]);
269: }
270:
271: protected void removeChild(String name) {
272: Assert.notNull("name", name);
273: if (!this .name2child.containsKey(name)) {
274: throw new RuntimeException("The node [" + name
275: + "] is not contained!");
276: }
277: SiteNode node = (SiteNode) this .name2child.get(name);
278: this .name2child.remove(node.getName());
279: this .children.remove(node);
280: getTree().nodeRemoved(getPath() + "/" + name);
281: deleteIfEmpty();
282: }
283:
284: private Map name2child = new HashMap();
285:
286: public SiteNode addChild(String name, boolean visible) {
287: Assert.notNull("name", name);
288: return addChild(name, this .children.size(), visible);
289: }
290:
291: public SiteNode addChild(String name, String followingNodeName,
292: boolean visible) {
293: Assert.notNull("name", name);
294: Assert.notNull("following node name", followingNodeName);
295: SiteNode followingSibling = getChild(followingNodeName);
296: int pos = this .children.indexOf(followingSibling);
297: return addChild(name, pos, visible);
298: }
299:
300: protected SiteNode addChild(String name, int pos, boolean visible) {
301: Assert.notNull("name", name);
302:
303: if (this .name2child.containsKey(name)) {
304: throw new RuntimeException("The child [" + name
305: + "] is already contained.");
306: }
307:
308: SiteNode node = new TreeNodeImpl(this , name, visible,
309: getLogger());
310: this .children.add(pos, node);
311: this .name2child.put(name, node);
312: getTree().nodeAdded(node);
313: getTree().changed();
314: return node;
315: }
316:
317: protected SiteNode getChild(String name) {
318: Assert.notNull("name", name);
319: if (this .name2child.containsKey(name)) {
320: return (SiteNode) this .name2child.get(name);
321: } else {
322: throw new RuntimeException("No such child [" + name + "]");
323: }
324: }
325:
326: protected int getPosition(SiteNode child) {
327: Assert.notNull("child", child);
328: Assert.isTrue("contains", this .children.contains(child));
329: return this .children.indexOf(child);
330: }
331:
332: public void moveDown(String name) {
333: SiteNode child = getChild(name);
334: int pos = getPosition(child);
335: Assert.isTrue("not last", pos < this .children.size() - 1);
336: this .children.remove(child);
337: this .children.add(pos + 1, child);
338: changed();
339: }
340:
341: public void moveUp(String name) {
342: SiteNode child = getChild(name);
343: int pos = getPosition(child);
344: Assert.isTrue("not first", pos > 0);
345: this .children.remove(child);
346: this .children.add(pos - 1, child);
347: changed();
348: }
349:
350: public String getHref() {
351: return null;
352: }
353:
354: public String getSuffix() {
355: return null;
356: }
357:
358: public boolean hasLink() {
359: return false;
360: }
361:
362: }
|