001/**
002 * Copyright 2011 Bill Brown
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package com.colorfulsoftware.rss;
017
018import java.io.Serializable;
019import java.util.LinkedList;
020import java.util.List;
021
022/**
023 * <p>
024 * The external namespace extension element.
025 * </p>
026 * <p>
027 * From the <a href="http://cyber.law.harvard.edu/rss/rss.html">RSS 2.0
028 * specification</a>...
029 * </p>
030 * <p>
031 * This class can be used to add extended namespace elements.
032 * </p>
033 * 
034 * @author Bill Brown
035 * 
036 */
037public class Extension implements Serializable {
038
039        /**
040         * 
041         */
042        private static final long serialVersionUID = 7382104018423864548L;
043        private final String elementName;
044        private final List<Attribute> attributes;
045        private final String content;
046        private final String namespacePrefix;
047
048        Extension(String elementName, List<Attribute> attributes, String content)
049                        throws RSSpectException {
050
051                this.elementName = elementName;
052
053                this.content = content;
054
055                if (attributes == null) {
056                        this.attributes = null;
057                } else {
058                        this.attributes = new LinkedList<Attribute>();
059                        for (Attribute attr : attributes) {
060                                this.attributes.add(new Attribute(attr));
061                        }
062                }
063
064                if (elementName == null
065                                || elementName.equals("")
066                                || (elementName.indexOf(":") == -1 && getAttribute("xmlns") == null)
067                                || elementName.indexOf(":") == 0) {
068
069                        throw new RSSpectException(
070                                        "Extension element '"
071                                                        + elementName
072                                                        + "' is missing a namespace prefix or namespace declaration.");
073                }
074
075                // the namespace prefix is used here for validation only.
076                if (elementName.indexOf(":") != -1) {
077                        String potentialPrefix = elementName.substring(0, elementName
078                                        .indexOf(":"));
079                        if (getAttribute("xmlns:" + potentialPrefix) == null) {
080                                this.namespacePrefix = potentialPrefix;
081                        } else {
082                                this.namespacePrefix = null;
083                        }
084                } else {
085                        this.namespacePrefix = null;
086                }
087        }
088
089        Extension(Extension extension) {
090                this.elementName = extension.elementName;
091                this.attributes = extension.getAttributes();
092                this.content = extension.content;
093                this.namespacePrefix = extension.namespacePrefix;
094        }
095
096        /**
097         * 
098         * @return the attribute list.
099         */
100        public List<Attribute> getAttributes() {
101
102                List<Attribute> attrsCopy = new LinkedList<Attribute>();
103                if (this.attributes != null) {
104                        for (Attribute attr : this.attributes) {
105                                attrsCopy.add(new Attribute(attr));
106                        }
107                }
108                return (this.attributes == null) ? null : attrsCopy;
109        }
110
111        /**
112         * @return the content.
113         */
114        public String getContent() {
115                return content;
116        }
117
118        /**
119         * @return the extension element name. eg "atom:link" or "someExtension"
120         */
121        public String getElementName() {
122                return elementName;
123        }
124
125        /**
126         * @param attrName
127         *            the name of the attribute to get.
128         * @return the Attribute object if attrName matches or null if not found.
129         */
130        public Attribute getAttribute(String attrName) {
131                if (this.attributes != null) {
132                        for (Attribute attribute : this.attributes) {
133                                if (attribute.getName().equals(attrName)) {
134                                        return new Attribute(attribute);
135                                }
136                        }
137                }
138                return null;
139        }
140
141        /**
142         * Shows the contents of the extension element.
143         */
144        @Override
145        public String toString() {
146                StringBuilder sb = new StringBuilder("<" + elementName);
147                if (attributes != null) {
148                        for (Attribute attribute : attributes) {
149                                sb.append(attribute);
150                        }
151                }
152
153                if (content == null || content.equals("")) {
154                        sb.append(" />");
155                } else {
156                        sb.append(" >" + content + "</" + elementName + ">");
157                }
158
159                return sb.toString();
160        }
161
162        String getNamespacePrefix() {
163                return namespacePrefix;
164        }
165        
166        @Override
167        public boolean equals(Object obj) {
168                if (obj == this) {
169                        return true;
170                }
171                if (!(obj instanceof Extension)) {
172                        return false;
173                }
174                return this.toString().equals(obj.toString());
175        }
176        
177        @Override public int hashCode() {
178                return toString().hashCode();
179        }
180}