001    /*
002     * Copyright 1999,2004 The Apache Software Foundation.
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     */
016    
017    package org.apache.commons.feedparser;
018    
019    import java.util.Date;
020    
021    import org.apache.commons.feedparser.tools.ISO8601DateParser;
022    import org.apache.commons.feedparser.tools.RFC822DateParser;
023    import org.jdom.Element;
024    import org.jdom.Namespace;
025    
026    /**
027     * Handles parsing RSS metadata including dates
028     *
029     * @author <a href="mailto:burton@apache.org">Kevin A. Burton (burtonator)</a>
030     * @version $Id: MetaFeedParser.java 373879 2006-01-31 17:23:15Z mvdb $
031     */
032    public class MetaFeedParser extends BaseParser {
033    
034        /**
035         * 
036         */
037        public static void parse( FeedParserListener listener,
038                                  FeedParserState state ) throws FeedParserException {
039    
040            //FIXME: this should be refactored into a new class called
041            //MetaFeedParser to be used by both Atom and RSS.  Also the date
042            //handling below needs to be generic.
043            
044            if ( listener instanceof MetaFeedParserListener == false )
045                return;
046    
047            MetaFeedParserListener mfp = (MetaFeedParserListener)listener;
048    
049            parseDate( state, mfp );
050            
051            //FIXME: make sure RSS .9 is working and 0.91.  I just need to confirm
052            //but I think they are working correctly
053            parseGUID( state, mfp );
054    
055            parseAuthor( state, mfp );
056    
057            parseComments( state, mfp );
058    
059            parseCommentsFeed( state, mfp );
060            
061        }
062    
063        private static void parseComments( FeedParserState state,
064                                           MetaFeedParserListener listener )
065            throws FeedParserException {
066    
067            Element element = state.current.getChild( "comments" );
068    
069            if ( element != null ) {
070    
071                String resource = element.getText();
072                listener.onComments( state, resource );
073                listener.onCommentsEnd();
074                
075            }
076            
077        }
078    
079        private static void parseCommentsFeed( FeedParserState state,
080                                               MetaFeedParserListener listener )
081            throws FeedParserException {
082    
083            Element element = state.current.getChild( "commentRSS", NS.WFW );
084    
085            if ( element != null ) {
086    
087                String resource = element.getText();
088                listener.onCommentsFeed( state, resource );
089                listener.onCommentsFeedEnd();
090                
091            }
092    
093        }
094    
095        private static void parseAuthor( FeedParserState state,
096                                         MetaFeedParserListener listener )
097            throws FeedParserException {
098    
099            Element element = null;
100    
101            String name = null;
102            String email = null;
103            String resource = null;
104    
105            try {
106                
107                //atom:author
108    
109                element = state.current.getChild( "author", NS.ATOM );
110    
111                if ( element != null ) {
112                    name = selectText( "atom:name", element );
113                    email = selectText( "atom:email", element );
114                    resource = selectText( "atom:uri", element );
115                }
116    
117                //dc:creator (RSS 1.0)
118                element = state.current.getChild( "creator", NS.DC );
119    
120                if ( element != null )
121                    name = element.getText();
122                    
123                //author (RSS 2.0)
124                element = state.current.getChild( "author" );
125    
126                if ( element != null )
127                    name = element.getText();
128    
129                if ( name != null && ! "".equals( name ) ) {
130    
131                    listener.onAuthor( state,
132                                       name,
133                                       email,
134                                       resource );
135                    
136                    listener.onAuthorEnd();
137    
138                }
139    
140            } catch ( Exception e ) {
141                throw new FeedParserException( e );
142            }
143    
144        }
145    
146        private static void parseGUID( FeedParserState state,
147                                       MetaFeedParserListener listener )
148            throws FeedParserException {
149    
150            Element id = null;
151    
152            String guid = null;
153            boolean isPermalink = false;
154            
155            id = state.current.getChild( "id", NS.ATOM );
156    
157            if ( id != null ) {
158                guid = id.getText();
159            }
160    
161            id = state.current.getChild( "guid" );
162    
163            if ( id != null ) {
164    
165                guid = id.getText();
166                isPermalink = "true".equals( id.getAttributeValue( "isPermalink" ) );
167                
168            }
169    
170            if ( guid != null ) {
171    
172                listener.onGUID( state,
173                                 guid,
174                                 isPermalink );
175                
176                listener.onGUIDEnd();
177    
178            }
179            
180        }
181    
182        private static void parseDate( FeedParserState state,
183                                       MetaFeedParserListener listener )
184            throws FeedParserException {
185    
186            if ( parseDate( "date", NS.DC, listener, state ) )
187                return;
188    
189            // http://www.mnot.net/drafts/draft-nottingham-atom-format-02.html#rfc.section.4.13.8
190            // 
191            // The "atom:created" element is a Date construct that indicates the
192            // time that the entry was created. atom:entry elements MAY contain
193            // an atom:created element, but MUST NOT contain more than one.
194    
195            // The content of an atom:created element MUST have a time zone
196            // whose value SHOULD be "UTC".
197            
198            if ( parseDate( "created", NS.ATOM, listener, state ) )
199                return;
200    
201            // http://www.mnot.net/drafts/draft-nottingham-atom-format-02.html#rfc.section.4.13.8
202            //            
203            // If atom:created is not present, its content MUST considered to be
204            // the same as that of atom:modified.
205    
206            if ( parseDate( "modified", NS.ATOM, listener, state ) )
207                return;
208    
209            //support RSS 2.0 and RSS 0.9x dates.
210    
211            if ( parseDate( "pubDate", null, listener, state, false ) )
212                return;
213    
214        }
215        
216        private static boolean parseDate( String name,
217                                          Namespace ns,
218                                          MetaFeedParserListener listener,
219                                          FeedParserState state ) {
220    
221            return parseDate( name, ns, listener, state, true );
222    
223        }
224        
225        private static boolean parseDate( String name,
226                                          Namespace ns,
227                                          MetaFeedParserListener listener,
228                                          FeedParserState state,
229                                          boolean ISO8601 ) {
230            try { 
231                //ok.  Support dc:date
232                String v = state.current.getChildText( name, ns );
233        
234                if ( v != null ) {
235                        
236                    Date d = null;
237                    if ( ISO8601 ) {
238                        d = ISO8601DateParser.parse( v );
239                    } else {
240                        d = RFC822DateParser.parse( v );
241                    }
242    
243                    listener.onCreated( state, d );
244                    listener.onCreatedEnd();
245    
246                    return true;
247                }
248            } catch ( Throwable t ) {
249                // ignore the exception, so we can just move on
250            }
251    
252            return false;
253    
254        }
255    
256    }